package com.blue.integration.serve.aliyun;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.model.OSSObject;
import com.blue.core.id.IdGenerator;
import com.blue.core.util.UrlUtil;
import com.blue.integration.serve.Bucket;
import com.blue.integration.serve.StorageClient;
import com.blue.integration.serve.StorageException;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * 阿里云OSS存储
 *
 * @author zhengjin
 * @since 1.0 2017年11月15日
 */
public class AliyunStorageClient implements StorageClient, InitializingBean, DisposableBean
{
	private static Logger logger = LoggerFactory.getLogger(AliyunStorageClient.class);

	private String internalEndpoint;
	private String endpoint;
	private String accessId;
	private String accessKey;
	private boolean https = false;
	private OSSClient client;
	private Map<Bucket, String> bucketMap;

	public AliyunStorageClient()
	{
	}

	@Override
	public String save(Bucket bucket, File file, String key) throws IOException
	{
		Assert.notNull(file, "文件不能为空");
		if (key == null || key.isEmpty())
		{
			key = this.getKey(file.getName());
		}
		String bucketName = this.getBucketName(bucket);
		client.putObject(bucketName, key, file);
		logger.info("成功上传文件：{}", key);
		return key;
	}

	@Override
	public String save(Bucket bucket, InputStream is, String name, String key) throws IOException
	{
		Assert.notNull(is, "文件输入流不能为空");
		if (key == null || key.isEmpty())
		{
			key = this.getKey(name);
		}
		String bucketName = this.getBucketName(bucket);
		try (InputStream iis = is)
		{
			client.putObject(bucketName, key, iis);
		}
		logger.info("成功上传文件：{}", key);
		return key;
	}

	@Override
	public void delete(Bucket bucket, String key)
	{
		Assert.hasText(key, "文件 Key 不能为空");
		String bucketName = this.getBucketName(bucket);
		client.deleteObject(bucketName, key);
		logger.info("成功删除文件：{}", key);
	}

	@Override
	public File download(Bucket bucket, String key, File dest) throws IOException
	{
		Assert.hasText(key, "文件 Key 不能为空");
		String bucketName = this.getBucketName(bucket);
		if (dest == null)
		{
			String path = UrlUtil.getTempDir() + IdGenerator.uuid12bit() + UrlUtil.getFileExt(key);
			dest = new File(path);
		}
		if (!dest.getParentFile().exists())
		{
			if (!dest.getParentFile().mkdirs())
				throw new StorageException("无法创建目录：" + dest.getParent());
		}
		OSSObject object = client.getObject(bucketName, key);
		try (InputStream is = object.getObjectContent();
		     FileOutputStream os = new FileOutputStream(dest))
		{
			IOUtils.copyLarge(is, os);
		}
		logger.info("成功下载文件，源：{}，目标：{}", key, dest.getAbsolutePath());
		return dest;
	}

	@Override
	public InputStream getStream(Bucket bucket, String key) throws IOException
	{
		Assert.hasText(key, "文件 Key 不能为空");
		String bucketName = this.getBucketName(bucket);
		OSSObject object = client.getObject(bucketName, key);
		return object.getObjectContent();
	}

	@Override
	public String getString(Bucket bucket, String key) throws IOException
	{
		Assert.hasText(key, "文件 Key 不能为空");
		String bucketName = this.getBucketName(bucket);
		OSSObject object = client.getObject(bucketName, key);
		String content = null;
		try (InputStream is = object.getObjectContent();)
		{
			content = IOUtils.toString(is, "UTF-8");
		}
		return content;
	}

	@Override
	public String getUrl(Bucket bucket, String key)
	{
		if (key == null || key.isEmpty())
			return null;

		String bucketName = this.getBucketName(bucket);
		String http = https ? "https://" : "http://";
		StringBuilder url = new StringBuilder(64);
		url.append(http).append(bucketName).append(".");
		url.append(endpoint).append("/").append(key);
		return url.toString();
	}

	@Override
	public String getKey(String name)
	{
		String ext = UrlUtil.getFileExt(name);
		return IdGenerator.uuid12bit() + ext;
	}

	private String getBucketName(Bucket bucket)
	{
		Assert.notNull(bucket, "Bucket 不能为空");
		if (bucketMap == null || bucketMap.isEmpty())
			return bucket.name().toLowerCase();

		String bucketName = bucketMap.get(bucket);
		if (bucketName != null && !bucketName.isEmpty())
			return bucketName;

		return bucket.name().toLowerCase();
	}

	@Override
	public void afterPropertiesSet() throws Exception
	{
		if (endpoint == null || endpoint.isEmpty())
			throw new StorageException("配置 endpoint 不能为空");
		if (accessId == null || accessId.isEmpty())
			throw new StorageException("配置 accessId 不能为空");
		if (accessKey == null || accessKey.isEmpty())
			throw new StorageException("配置 accessKey 不能为空");

		if (internalEndpoint == null || internalEndpoint.isEmpty())
			internalEndpoint = endpoint;

		client = new OSSClient(internalEndpoint, new DefaultCredentialProvider(accessId, accessKey), null);
		logger.info("初始化 AliyunStorageClient");
	}

	@Override
	public void destroy() throws Exception
	{
		if (client != null)
		{
			client.shutdown();
		}
		logger.info("关闭 AliyunStorageClient");
	}

	public void setInternalEndpoint(String internalEndpoint)
	{
		this.internalEndpoint = internalEndpoint;
	}

	public void setEndpoint(String endpoint)
	{
		this.endpoint = endpoint;
	}

	public void setAccessId(String accessId)
	{
		this.accessId = accessId;
	}

	public void setAccessKey(String accessKey)
	{
		this.accessKey = accessKey;
	}

	public void setHttps(boolean https)
	{
		this.https = https;
	}

	public void setBucketMap(Map<Bucket, String> bucketMap)
	{
		this.bucketMap = bucketMap;
	}

}
